package com.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ZhouyuApplicationContext {


    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    private Map<String, Object> singletonObjects = new HashMap<>();

    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public ZhouyuApplicationContext(Class configClass) {

        //扫描包路径
        scan(configClass);

        //设置单例bean的单例map
        setSingletonObjects();


    }

    private void setSingletonObjects() {
        for (Map.Entry<String, BeanDefinition> beanEntry : beanDefinitionMap.entrySet()) {
            String beanName = beanEntry.getKey();
            BeanDefinition beanDefinition = beanEntry.getValue();
            if (beanDefinition.getScopeEnum() == ScopeEnum.singleton) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanEntry.getKey(), bean);
            }
        }
    }

    /**
     * 扫描包路径
     *
     * @param configClass
     */
    private void scan(Class configClass) {

        ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String componentScanValue = componentScan.value();
        String relatePth = componentScanValue.replace(".", "/");
        ClassLoader classLoader = ZhouyuApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(relatePth);
        File file = new File(resource.getFile());
        //证明是文件夹
        if (!file.isFile()) {
            for (File listFile : file.listFiles()) {
                String absolutePath = listFile.getAbsolutePath();
                String str = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));

                String osName = System.getProperty("os.name");
                String replace = "";
                if(osName.startsWith("Windows")){
                    replace = str.replace("\\", ".");
                }else if(osName.startsWith("Mac")){
                    replace = str.replace("/", ".");
                }

                try {
                    Class<?> beanClass = classLoader.loadClass(replace);

                    //表示在类的注解上有Component,表示是一个 bean,否则不进行操作
                    if (beanClass.isAnnotationPresent(Component.class)) {
                        //判断BeanPostProcessor 放到一个 list中去
                        if (BeanPostProcessor.class.isAssignableFrom(beanClass)) {
                            BeanPostProcessor beanPostProcessor = (BeanPostProcessor) beanClass.getConstructor().newInstance();
                            beanPostProcessorList.add(beanPostProcessor);
                        }

                        String beanName = beanClass.getAnnotation(Component.class).value();

                        if ("".equals(beanName)) {
                            beanName = Introspector.decapitalize(beanClass.getSimpleName());

                        }
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setBeanClass(beanClass);
                        //判断是否有Scope ，有则取Scope的值
                        if (beanClass.isAnnotationPresent(Scope.class)) {
                            ScopeEnum scopeVal = beanClass.getAnnotation(Scope.class).value();
                            beanDefinition.setScopeEnum(scopeVal);
                        } else {
                            //否则则直接是单例的
                            beanDefinition.setScopeEnum(ScopeEnum.singleton);

                        }

                        beanDefinitionMap.put(beanName, beanDefinition);

                    }

                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Object createBean(String beanName, BeanDefinition beanDefinition) {
        //创建新的bean
        Class beanClass = beanDefinition.getBeanClass();
        Object instance = null;
        try {
            instance = beanClass.getConstructor().newInstance();
            //此处是依赖注入的灵魂

            for (Field field : beanClass.getDeclaredFields()) {
                //只有 Autowired的才进行属性初始化
                if (field.isAnnotationPresent(Autowired.class)) {
                    field.setAccessible(true);
                    //此处先判断一下如果是String 类型就忽略
                    if(field.getType().getName().equals("java.lang.String")){
                        continue;
                    }
                    field.set(instance, getBean(field.getName()));
                }

            }

            //针对 spring BeanNameAware的使用
            if(instance instanceof BeanNameAware){
                ((BeanNameAware)instance).setBeanName(beanName);
            }

            //初始化前的 beanPostProcessor循环调用
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
            }

            //初始化的简单实现
            if (instance instanceof InitializingBean) {
                ((InitializingBean) instance).afterPropertiesSet();
            }

            //初始化后的 beanPostProcessor循环调用
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }


        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;

    }

    public Object getBean(String beanName) {
        if (!beanDefinitionMap.containsKey(beanName)) {
            throw new NullPointerException();
        }
        //判断如果是单例bean 还是多例bean 如果是单例的一种处理方法，如果是多例的是另外一种
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScopeEnum() == ScopeEnum.singleton) {
            Object singletonBean = singletonObjects.get(beanName);
            if (singletonBean == null) {
                singletonBean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, singletonBean);
            }
            return singletonBean;

        } else {
            //有一个创建bean的方法
            Object o = createBean(beanName, beanDefinition);
            return o;
        }


    }
}











